import { App, createApp, defineAsyncComponent, ref } from 'vue'
import { isFunc } from '../base'
import UiDialog from './dialog.vue'
import { h } from 'vue'
import { DialogProps, ElConfigProvider } from 'element-plus'
import { KeyValues, ModalForm, OptionalMutable } from '../types'
import zhCn from 'element-plus/es/locale/lang/zh-cn'
import { NavigationGuardNext } from 'vue-router'
import { setForceNav, state } from '../store'

type OpenFuncOptions = {
  vm: any,
  vmProps?: any,
  dialogProps?: OptionalMutable<DialogProps> & InstanceType<typeof UiDialog>['$props'] & KeyValues<any>
}

export const openDialog = (options: OpenFuncOptions) => {
  const vm = isFunc(options.vm) ? defineAsyncComponent(options.vm) : options.vm
  const slotRef = ref<ModalForm>()

  let app: App<Element> | null = createApp({
    render () {
      const dialogProps: OpenFuncOptions['dialogProps'] = {
        width: 420,
        alignCenter: true,
        appendToBody: true,
        closeOnClickModal: false,
        ...(options.dialogProps || {}),
        slotRef,
        onClosed: () => {
          this.$emit('closed')
          app?._container?.remove()
          app?.unmount()
          app = null
        }
      }
      return h(ElConfigProvider, { locale: zhCn }, {
        default: () => {
          return h(UiDialog, dialogProps, {
            default: () => {
              return h(vm, { ...(options.vmProps || {}), ref: slotRef })
            }
          })
        }
      })
    }
  })

  const div = document.createElement('div')
  document.body.appendChild(div)
  app.mount(div)
}

const getAllShowedModals = () => {
  return Array
    .from(document.body.querySelectorAll('.el-overlay'))
    .filter(el => {
      return window.getComputedStyle(el, null).display !== 'none'
    }) as HTMLElement[]
}

const closeModal = (el?: HTMLElement) => {
  if (el) {
    const closeBtnCls = '.el-dialog__close,.el-drawer__close,.el-message-box__headerbtn'
    const btnClose = el.querySelector(closeBtnCls) as HTMLButtonElement
    if (btnClose) {
      btnClose.click()
      return true
    }
  }
}

const closeTopModal = () => {
  return closeModal(
    getAllShowedModals()
      .reduce((t: HTMLElement | undefined, el) => {
        return t && +t.style.zIndex > +el.style.zIndex ? t : el
      }, undefined)
  )
}

const closeAllModals = () => getAllShowedModals().reverse().forEach(closeModal)

export const navInterceptor = (next: NavigationGuardNext) => {
  if (state.forceNav) {
    setForceNav(false)
    closeAllModals()
  } else if (closeTopModal()) {
    return next(false)
  }
  next()
}
